package cat.joronya.supermanager.service.htmlcleanerImpl;

import java.io.StringWriter;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.auth.AuthenticationException;
import org.htmlcleaner.ContentNode;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;

import android.util.Log;
import cat.joronya.supermanager.Supermanager;
import cat.joronya.supermanager.service.ClosedChangesException;
import cat.joronya.supermanager.service.ClosedWebException;
import cat.joronya.supermanager.service.LoginParser;

public class LoginParserImpl implements LoginParser
{
	// XPATHs per treure dades de les pagines
	// login error XPATH
	private static final String LOGIN_ERROR_XPATH = "//img[@src='gif/registrar.gif']";
	// jornada XPATH
	private static final String LOGIN_JORNADA_XPATH = "//td[@class='blanca15']";
	// canvis tancats init page XPATH
	private static final String LOGIN_CANVIS_TANCATS_INIT_PAGE_XPATH = "//td[@class='blanco']";
	// canvis tancats XPATH
	private static final String LOGIN_CANVIS_TANCATS_XPATH = "//small[b='Cambios cerrados']";
	// supermanager tancat msg: "El juego estará cerrado durante unos minutos"
	private static final String LOGIN_SM_TANCAT_XPATH = "//td/text()[last()]";
	// supermanaget tancat sense carcassa "<b>SUPERMANAGER CERRADO TEMPORALMENTE</b>"
	private static final String LOGIN_SM_NC_TANCAT_XPATH = "//b/text()";
	
	// data parsed
	public String jornada = null;
	public String nextJornada = null;
	public Timestamp duetime = null;
	public String homeInfo = null;
	public int status = -1;
	
	public long parse(String html)
	{
		long start = System.nanoTime();
		
		try
		{
			HtmlCleaner cleaner = new HtmlCleaner();
			TagNode node = cleaner.clean(html);
	        
	        // login error?
	        Object[] tdError = node.evaluateXPath(LOGIN_ERROR_XPATH);
	        if( tdError.length > 0 )
	        {
	        	TagNode tagError = (TagNode)tdError[0];
	        	if( "img".equals(tagError.getName()) )
	        		throw new AuthenticationException();
	        }
	        
	        // mirem si supermanager tancat temporalment
	        Object[] smTancat = node.evaluateXPath(LOGIN_SM_TANCAT_XPATH);
	        if( smTancat.length != 0 && "El juego estará cerrado durante unos minutos".equals(smTancat[0].toString()))
	        {
	        	throw new ClosedWebException();
	        }
	        
	        // mirem si supermanager tancat temporalment sense carcassa
	        Object[] smNCTancat = node.evaluateXPath(LOGIN_SM_NC_TANCAT_XPATH);
	        if( smNCTancat.length != 0 && "SUPERMANAGER CERRADO TEMPORALMENTE".equals(smNCTancat[0].toString()))
	        {
	        	throw new ClosedWebException();
	        }
	        
	        // mirem si estan els canvis tancats init page
	        Object[] CanvisTancatsIP = node.evaluateXPath(LOGIN_CANVIS_TANCATS_INIT_PAGE_XPATH);
	        if( CanvisTancatsIP.length != 0 )
	        {
	        	try
	        	{
	        		TagNode tdCanvisTancatsIP = (TagNode)CanvisTancatsIP[0];
	        		TagNode pCanvisTancatsIP = tdCanvisTancatsIP.getChildTags()[0];
	        		TagNode fontCanvisTancatsIP = pCanvisTancatsIP.getChildTags()[0];
	        		TagNode bCanvisTancatsIP = fontCanvisTancatsIP.getChildTags()[0];
	        		List bCanvisTancatsIPChilds = bCanvisTancatsIP.getChildren();
	        		ContentNode canvisTancats = (ContentNode)bCanvisTancatsIPChilds.get(0);
	        		if( "SUPERMANAGER CERRADO TEMPORALMENTE".equals(canvisTancats.toString()))
	        			throw new ClosedWebException();
	        	}
	        	catch(ClosedWebException e){
	        		throw e;
	        	}
	        	catch(Exception e){
	        		// nothing, if error continue
	        	}
	        }
	        
	        // cerquem la jornada i el home info
	        Object[] tdJornada = node.evaluateXPath(LOGIN_JORNADA_XPATH);
	        if( tdJornada.length > 0)
	        {
	        	// cerquem jornada
	        	TagNode tagJornada = (TagNode)tdJornada[0];
	        	for(Object obj: tagJornada.getChildren())
	        	{
	        		if(obj instanceof ContentNode)
	        		{
	        			jornada = obj.toString();
	        			jornada = jornada.replaceFirst("Jornada ", "");
	        			Log.d(Supermanager.TAG,"LoginSync parsing jornada: "+jornada);
	        		}
	        	}
	        	// des d'aqui la home info tambe
	        	List tableBodyHomeInfoChildren = tagJornada.getParent().getParent().getChildren();
	        	TagNode tableBodyHomeInfoTr = (TagNode)tableBodyHomeInfoChildren.get(1);
	        	// saltem el tr del compte enrera pels canvis
	        	TagNode tableBodyHomeInfoTrTd0 = tableBodyHomeInfoTr.getChildTags()[0];
	        	TagNode tableBodyHomeInfoTrTd0Child0 = tableBodyHomeInfoTrTd0.getChildTags()[0];
	        	// si es el del countdown agafem el seguent
	        	if( "br".equals(tableBodyHomeInfoTrTd0Child0.getName()) )
	        		tableBodyHomeInfoTr = (TagNode)tableBodyHomeInfoChildren.get(2);
	        	
	        	int tableIndex = 0;
	        	for(Object obj: tableBodyHomeInfoTr.getChildren())
	        	{
	        		TagNode tdHomeInfo = (TagNode)obj;
	        		if( !"td".equals(tdHomeInfo.getName()) )
	        			continue;
	        		
	        		// List tdHomeInfoChildren = tdHomeInfo.getChildren();
	        		for(Object tableHomeInfo: tdHomeInfo.getChildren())
	        		{
	        			// saltem textes
	        			if( tableHomeInfo instanceof ContentNode )
	        				continue;
	        			
	        			//TagNode tableHomeInfo = (TagNode)tdHomeInfoChildren.get(0);
	        			TagNode tableHomeInfoTagNode = (TagNode)tableHomeInfo;
	        			if( !"table".equals(tableHomeInfoTagNode.getName()) )
	        				continue;
	        			
	        			// home info
	        			if( tableIndex == 0 )
	        			{
	        				// serialitzem el tagnode i fills.
	        				SimpleHtmlSerializer htmlSerializer = new SimpleHtmlSerializer(cleaner.getProperties());
	        				StringWriter stringWriter = new StringWriter();
	        				htmlSerializer.write(tableHomeInfoTagNode, stringWriter, "utf-8");
	        				this.homeInfo = stringWriter.toString();
	        			}
	        			
	        			// close changes
	        			if( tableIndex == 1 )
	        			{
	        				List ccTableBodies = tableHomeInfoTagNode.getChildren();
	        				TagNode ccTableBody = (TagNode)ccTableBodies.get(0);
	        				List ccTrs = ccTableBody.getChildren();
	        				TagNode ccTr = (TagNode)ccTrs.get(0);
	        				List ccTds = ccTr.getChildren();
	        				TagNode ccTd = (TagNode)ccTds.get(1);
	        				
	        				int spanIndex = 0;
	        				for(Object spanObject: ccTd.getChildren())
	        				{
	        					if( !(spanObject instanceof TagNode) )
	        						continue;
	        					
	        					TagNode spanNode = (TagNode)spanObject;

	        					if( !"span".equals(spanNode.getName()) )
	        						continue;
		        					
	        					
	        					if( spanIndex == 0 )	
	        					{
	        						Object spanJornadaObject = spanNode.getChildren().get(0);
	        						if( spanJornadaObject instanceof ContentNode )
	        						{
	        							nextJornada = ((ContentNode)spanJornadaObject).toString();
	        							nextJornada = nextJornada.replace("ª JORNADA", "");
	        							Log.d(Supermanager.TAG, "loginSync nextJornada: "+nextJornada);
	        						}
	        						else
	        						{
	        							throw new Exception();
	        						}
	        					}
	        					
	        					if( spanIndex == 1 )
	        					{
	        						// tag del dia/hora de tancament
	        						Object spanDuetimeObject = spanNode.getChildren().get(0);
	        						if( spanDuetimeObject instanceof ContentNode )
	        						{
	        							Pattern p = Pattern.compile("([^\\s]*)\\s([^/]*)/([^,]*),\\s([^:]*):([^\\s]*)\\sh");
	        	        				Matcher m = p.matcher(((ContentNode)spanDuetimeObject).toString());
	        	        				if( m.find() ) 
	        	        				{	try
	        	        					{
	        	        						Calendar cToday = new GregorianCalendar();
	        	        						cToday.setTime(new Date());
	        	        						int year = cToday.get(Calendar.YEAR);
	        	        						// ??? els mesos conten començant per 0
	        	        						int month = Integer.parseInt(m.group(3))-1;
	        	        						// si el mes es menor q el de la data, next day es de l'any q ve
	        	        						Log.d(Supermanager.TAG, "LoginSync today month: "+cToday.get(Calendar.MONTH)+", date month: "+month);
	        	        						if( month < cToday.get(Calendar.MONTH) )
	        	        							year ++;
	        	        						int day = Integer.parseInt(m.group(2));
	        	        						int hour = Integer.parseInt(m.group(4));
	        	        						int minute = Integer.parseInt(m.group(5));
	        	        						Calendar calendar = new GregorianCalendar(year,month,day,hour,minute);
	        	        						duetime = new Timestamp(calendar.getTimeInMillis());
	        	        						Log.d(Supermanager.TAG,"loginSync duetime->year:"+year+", month: "+month+", day: "+day+
	        	        								", hour: "+hour+", minute: "+minute+
	        	        								"\nduetime: "+duetime+", getTime(): "+duetime.getTime()+
	        	        								"\ncalendar.getTimeInMillis(): "+calendar.getTimeInMillis());
	        	        					}
	        	        					catch(Exception e){}
	        	        				}
	        						}
	        						else
	        						{
	        							throw new Exception();
	        						}
	        					}
	        					spanIndex++;
	        				}
	        			}
		        		
		        		tableIndex++;
	        		}
	        	}
	        }
	        
	        
	        // mirem si estan els canvis tancats
	        Object[] bCanvisTancats = node.evaluateXPath(LOGIN_CANVIS_TANCATS_XPATH);
	        if( bCanvisTancats.length != 0 )
	        	throw new ClosedChangesException();
	        
	        if( duetime == null)
	        	throw new ClosedChangesException();
		}
		catch(Exception e) 
		{
			throw new RuntimeException(e);
		}
		// si ens hem connectat marquem que estem online
		status = Supermanager.OPEN_STATUS;
		return System.nanoTime()-start;
    }

	public String getJornada() {
		return jornada;
	}

	public String getNextJornada() {
		return nextJornada;
	}

	public Timestamp getDuetime() {
		return duetime;
	}

	public String getHomeInfo() {
		return homeInfo;
	}

	public int getStatus() {
		return status;
	}

}
